// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: xguo

#pragma once

#include <cstdio>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <unordered_map>

#include <rapidjson/document.h>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/base/order/product_info_cache.h"
#include "coin2/exchange/bybit_futures/symbology/currency.h"
#include "coin2/exchange/bybit_futures/symbology/product.h"

namespace coin2::exchange::bybit_futures::order_v2 {

class BybitFuturesParser : public base::order::BaseParser {
  using BybitFuturesProductInfoCache = coin2::exchange::base::order::ProductInfoCache<
      coin2::exchange::bybit_futures::symbology::BybitFuturesProduct,
      coin2::exchange::bybit_futures::symbology::BybitFuturesCurrency>;

 public:
  const ParseResult& ParseRawMessage(const RawMessage& msg) override;
  AccountBalance ParseBalance(const JsonValue& doc) override;
  AccountPosition ParsePosition(const JsonValue& doc) override;
  bool ParseRawBalance(const JsonValue& doc, RawBalanceMap* raw_balance_map);
  bool ParseRawPosition(const JsonValue& doc, RawPositionMap* raw_position_map);

 private:
  void ParseSubmitResponse();
  void ParseCancelResponse();
  void ParseRestOrdersInfo();
  void ParseRestFillInfoList();
  void ParseRestAccountBalance();
  void ParseRestAccountPosition();
  void ParseWsMessage();

  ProductOrderBundle ParseWsOrderInfoListV2(const JsonValue& data);
  ProductFillBundle ParseWsFillInfoListV2(const JsonValue& data);
  AccountBalance ParseBalanceFromWs(const JsonValue& doc);
  AccountPosition ParseAccountPositionFromWs(const JsonValue& doc);
  AccountPosition ParseNormalPositionFromWs(const JsonValue& doc);
  AccountPosition ParseLinearPositionFromWs(const JsonValue& doc);
  coin::proto::ProductPosition ParseProductPosition(const JsonValue& data);
  bool ParseProductPositionV2(const JsonValue& data, RawPositionMap* raw_position_map);
  coin::proto::ProductOrderElement ParseRestOrderInfo(const JsonValue& data);
  bool CompareLastBalance(const std::string& symbol, double total_balance, const JsonValue& doc);
  bool ParseLinearRawPosition(const JsonValue& doc, RawPositionMap* raw_position_map);
  bool ParseNormalRawPosition(const JsonValue& doc, RawPositionMap* raw_position_map);

 private:
  std::unordered_map<std::string, double> buy_pos_map_;
  std::unordered_map<std::string, double> buy_free_pos_map_;
  std::unordered_map<std::string, double> sell_pos_map_;
  std::unordered_map<std::string, double> sell_free_pos_map_;
  RawPositionMap position_cache_map_;
  bool is_account_balance_initialized_ = false;
  bool is_account_position_initialized_ = false;
  bool ignorable_position_event_ = false;

  // to handle abnormal balance
  std::map<std::string, double> last_total_balance_;
  std::map<std::string, int64_t> abnormal_balance_;
};

}  // namespace coin2::exchange::bybit_futures::order_v2
